package org.example;

import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.concurrent.TimeUnit;

public class VideoSplitterWithEncodingFix extends JFrame {

    public static void main(String[] args) {
        runVc();
    }

    private JTextField inputPathField;
    private JTextField outputPathField;
    private JTextField durationField;
    private JTextField intervalField;  // 新增：视频间隔输入框
    private JTextArea logArea;
    private JButton startButton;

    // 程序常量配置
    private static final int DEFAULT_DURATION = 12; // 默认切割时长12秒
    private static final int DEFAULT_INTERVAL = 0;  // 默认间隔0秒
    private static final int MIN_DURATION = 1;      // 最小切割时长限制
    private static final int MAX_DURATION = 600;    // 最大切割时长限制
    private static final int MIN_INTERVAL = 0;      // 最小间隔时间限制
    private static final int MAX_INTERVAL = 300;    // 最大间隔时间限制

    public VideoSplitterWithEncodingFix() {
        initUI();
        setTitle("视频切割工具");
        setSize(700, 550);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null); // 窗口居中
        setResizable(true); // 允许调整窗口大小
    }

    public void initUI() {
        // 主面板使用边界布局
        JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
        mainPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));

        // 配置面板 - 使用网格布局，从3行改为4行以容纳新增的间隔设置
        JPanel configPanel = new JPanel(new GridLayout(4, 1, 10, 10));
        
        // 1. 视频文件选择
        JPanel inputPanel = createPathSelectionPanel(
            "视频文件:", 
            "选择视频文件", 
            this::browseInputFile
        );
        inputPathField = (JTextField) inputPanel.getComponent(1);
        
        // 2. 输出文件夹选择
        JPanel outputPanel = createPathSelectionPanel(
            "输出文件夹:", 
            "选择输出文件夹", 
            this::browseOutputDir
        );
        outputPathField = (JTextField) outputPanel.getComponent(1);
        
        // 3. 切割时长设置（默认12秒）
        JPanel durationPanel = new JPanel(new BorderLayout(5, 5));
        durationPanel.add(new JLabel("切割时长:"), BorderLayout.WEST);
        
        JPanel durationInputPanel = new JPanel(new BorderLayout(5, 5));
        durationField = new JTextField(String.valueOf(DEFAULT_DURATION));
        // 为时长输入框添加焦点监听，自动选择内容便于修改
        durationField.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent e) {
                durationField.selectAll();
            }
        });
        durationInputPanel.add(durationField, BorderLayout.CENTER);
        durationInputPanel.add(new JLabel("秒/段"), BorderLayout.EAST);
        
        durationPanel.add(durationInputPanel, BorderLayout.CENTER);
        // 添加时长范围提示
        JLabel durationHint = new JLabel("(范围: " + MIN_DURATION + "-" + MAX_DURATION + "秒)");
        durationHint.setForeground(Color.GRAY);
        durationPanel.add(durationHint, BorderLayout.EAST);

        // 4. 新增：视频间隔设置（默认0秒）
        JPanel intervalPanel = new JPanel(new BorderLayout(5, 5));
        intervalPanel.add(new JLabel("视频间隔:"), BorderLayout.WEST);
        
        JPanel intervalInputPanel = new JPanel(new BorderLayout(5, 5));
        intervalField = new JTextField(String.valueOf(DEFAULT_INTERVAL));
        // 为间隔输入框添加焦点监听
        intervalField.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent e) {
                intervalField.selectAll();
            }
        });
        intervalInputPanel.add(intervalField, BorderLayout.CENTER);
        intervalInputPanel.add(new JLabel("秒"), BorderLayout.EAST);
        
        intervalPanel.add(intervalInputPanel, BorderLayout.CENTER);
        // 添加间隔范围提示
        JLabel intervalHint = new JLabel("(范围: " + MIN_INTERVAL + "-" + MAX_INTERVAL + "秒)");
        intervalHint.setForeground(Color.GRAY);
        intervalPanel.add(intervalHint, BorderLayout.EAST);

        // 添加所有配置项到配置面板
        configPanel.add(inputPanel);
        configPanel.add(outputPanel);
        configPanel.add(durationPanel);
        configPanel.add(intervalPanel);  // 添加间隔设置面板

        // 日志面板
        JPanel logPanel = new JPanel(new BorderLayout(5, 5));
        logPanel.add(new JLabel("处理日志:"), BorderLayout.NORTH);
        logArea = new JTextArea();
        logArea.setEditable(false);
        logArea.setLineWrap(true);
        // 设置字体为支持中文的字体，解决中文显示问题
        logArea.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        JScrollPane logScrollPane = new JScrollPane(logArea);
        logScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        logPanel.add(logScrollPane, BorderLayout.CENTER);

        // 按钮面板
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10));
        startButton = new JButton("开始切割");
        startButton.addActionListener(this::startSplitting);
        startButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        startButton.setPreferredSize(new Dimension(100, 30));

        JButton resetButton = new JButton("重置");
        resetButton.addActionListener(e -> resetForm());
        resetButton.setFont(new Font("微软雅黑", Font.PLAIN, 14));
        resetButton.setPreferredSize(new Dimension(80, 30));

        buttonPanel.add(startButton);
        buttonPanel.add(resetButton);

        // 组装主面板
        mainPanel.add(configPanel, BorderLayout.NORTH);
        mainPanel.add(logPanel, BorderLayout.CENTER);
        mainPanel.add(buttonPanel, BorderLayout.SOUTH);

        add(mainPanel);
    }

    /**
     * 创建路径选择面板的通用方法
     */
    public JPanel createPathSelectionPanel(String labelText, String buttonText, ActionListener listener) {
        JPanel panel = new JPanel(new BorderLayout(5, 5));
        panel.add(new JLabel(labelText), BorderLayout.WEST);
        
        JTextField textField = new JTextField();
        textField.setEditable(false); // 禁止手动输入路径，确保路径有效性
        panel.add(textField, BorderLayout.CENTER);
        
        JButton button = new JButton(buttonText);
        button.addActionListener(listener);
        panel.add(button, BorderLayout.EAST);
        
        return panel;
    }

    /**
     * 浏览选择视频文件
     */
    public void browseInputFile(ActionEvent e) {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setDialogTitle("选择要切割的视频文件");
        fileChooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
            @Override
            public boolean accept(File f) {
                return f.isDirectory() || 
                       f.getName().toLowerCase().matches(".*\\.(mp4|avi|mov|mkv|flv|wmv|mpg|mpeg)");
            }
            
            @Override
            public String getDescription() {
                return "视频文件 (*.mp4, *.avi, *.mov, *.mkv等)";
            }
        });

        int result = fileChooser.showOpenDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            inputPathField.setText(fileChooser.getSelectedFile().getAbsolutePath());
        }
    }

    /**
     * 浏览选择输出文件夹
     */
    public void browseOutputDir(ActionEvent e) {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setDialogTitle("选择输出文件夹");
        fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        
        // 如果已选择输入文件，默认打开输入文件所在目录
        if (!inputPathField.getText().isEmpty()) {
            File inputFile = new File(inputPathField.getText());
            fileChooser.setCurrentDirectory(inputFile.getParentFile());
        }

        int result = fileChooser.showOpenDialog(this);
        if (result == JFileChooser.APPROVE_OPTION) {
            outputPathField.setText(fileChooser.getSelectedFile().getAbsolutePath());
        }
    }

    /**
     * 重置表单
     */
    public void resetForm() {
        inputPathField.setText("");
        outputPathField.setText("");
        durationField.setText(String.valueOf(DEFAULT_DURATION));
        intervalField.setText(String.valueOf(DEFAULT_INTERVAL));  // 重置间隔时间
        logArea.setText("");
        startButton.setEnabled(true);
    }

    /**
     * 开始切割视频
     */
    public void startSplitting(ActionEvent e) {
        // 清空日志
        logArea.setText("");
        
        // 获取用户输入
        String inputPath = inputPathField.getText().trim();
        String outputDir = outputPathField.getText().trim();
        String durationText = durationField.getText().trim();
        String intervalText = intervalField.getText().trim();  // 获取间隔时间

        // 验证输入
        if (!validateInput(inputPath, outputDir, durationText, intervalText)) {  // 更新验证方法
            return;
        }

        // 解析切割时长和间隔时间
        int segmentDuration = Integer.parseInt(durationText);
        int intervalSeconds = Integer.parseInt(intervalText);  // 解析间隔时间
        
        // 禁用开始按钮防止重复点击
        startButton.setEnabled(false);

        // 在新线程中执行切割任务，避免UI冻结
        new Thread(() -> {
            try {
                log("===== 开始视频切割 =====");
                log("视频文件: " + new File(inputPath).getName());
                log("输出目录: " + outputDir);
                log("切割时长: " + segmentDuration + "秒/段");
                log("视频间隔: " + intervalSeconds + "秒");  // 显示间隔时间

                // 获取视频总时长
                long totalDuration = getVideoDuration(inputPath);
                log("视频总时长: " + formatDuration(totalDuration));

                // 计算切割段数（考虑间隔时间）
                int segmentCount = 0;
                long currentPosition = 0;
                
                // 计算实际可切割的段数
                while (currentPosition + segmentDuration <= totalDuration) {
                    segmentCount++;
                    currentPosition += segmentDuration + intervalSeconds;
                }
                
                if (segmentCount == 0) {
                    throw new Exception("视频时长小于切割时长，无法进行切割");
                }
                
                log("预计切割段数: " + segmentCount + "段");

                // 确保输出目录存在
                File outputDirectory = new File(outputDir);
                if (!outputDirectory.exists() && !outputDirectory.mkdirs()) {
                    throw new Exception("无法创建输出目录，请检查权限");
                }

                // 批量切割视频
                currentPosition = 0;  // 重置当前位置
                long segmentStartTimeTotal = System.currentTimeMillis();
                for (int i = 0; i < segmentCount; i++) {
                    int startSecond = (int) currentPosition;
                    int actualDuration = (startSecond + segmentDuration > totalDuration) 
                        ? (int) (totalDuration - startSecond) 
                        : segmentDuration;

                    String outputFileName = String.format("video_%03d.mp4", i + 1);
                    String outputFilePath = outputDir + File.separator + outputFileName;

                    log("\n处理第 " + (i + 1) + "/" + segmentCount + " 段:");
                    log("起始时间: " + formatDuration(startSecond));
                    log("持续时长: " + formatDuration(actualDuration));
                    log("输出文件: " + outputFileName);

                    // 执行切割
                    // 执行切割并记录用时
                    long segmentStartTime = System.currentTimeMillis();
                    cutVideoSegment(inputPath, outputFilePath, startSecond, actualDuration);
                    long segmentEndTime = System.currentTimeMillis();
                    long elapsedSeconds = (segmentEndTime - segmentStartTime) / 1000;
                    log("第 " + (i + 1) + " 段切割完成，用时："+elapsedSeconds+" 秒");
                    
                    // 移动到下一段的起始位置（当前位置 + 片段时长 + 间隔时间）
                    currentPosition += actualDuration + intervalSeconds;
                }
                long segmentEndTimeTotal = System.currentTimeMillis();
                long elapsedSecondsTotal = (segmentEndTimeTotal - segmentStartTimeTotal) / 1000;
                // 完成提示
                log("\n===== 所有视频切割完成 =====");
                int finalSegmentCount = segmentCount;
                SwingUtilities.invokeLater(() -> {
                    startButton.setEnabled(true);
                    JOptionPane.showMessageDialog(
                        this, 
                        "视频切割完成！共生成 " + finalSegmentCount + " 段视频，用时："+elapsedSecondsTotal+" 秒",
                        "操作成功", 
                        JOptionPane.INFORMATION_MESSAGE
                    );
                });

            } catch (Exception ex) {
                String errorMsg = "处理失败: " + ex.getMessage();
                log("\n" + errorMsg);
                SwingUtilities.invokeLater(() -> {
                    startButton.setEnabled(true);
                    JOptionPane.showMessageDialog(
                        this, 
                        errorMsg, 
                        "操作失败", 
                        JOptionPane.ERROR_MESSAGE
                    );
                });
            }
        }).start();
    }

    /**
     * 验证用户输入（增加间隔时间验证）
     */
    public boolean validateInput(String inputPath, String outputDir, String durationText, String intervalText) {
        // 验证视频文件
        if (inputPath.isEmpty()) {
            showError("请选择要切割的视频文件");
            return false;
        }
        File inputFile = new File(inputPath);
        if (!inputFile.exists() || !inputFile.isFile()) {
            showError("选择的视频文件不存在或不是有效文件");
            return false;
        }

        // 验证输出目录
        if (outputDir.isEmpty()) {
            showError("请选择输出文件夹");
            return false;
        }

        // 验证切割时长
        try {
            int duration = Integer.parseInt(durationText);
            if (duration < MIN_DURATION || duration > MAX_DURATION) {
                showError("切割时长必须在 " + MIN_DURATION + "-" + MAX_DURATION + " 秒之间");
                durationField.requestFocus();
                return false;
            }
        } catch (NumberFormatException ex) {
            showError("切割时长必须是有效的整数");
            durationField.requestFocus();
            return false;
        }

        // 新增：验证间隔时间
        try {
            int interval = Integer.parseInt(intervalText);
            if (interval < MIN_INTERVAL || interval > MAX_INTERVAL) {
                showError("视频间隔必须在 " + MIN_INTERVAL + "-" + MAX_INTERVAL + " 秒之间");
                intervalField.requestFocus();
                return false;
            }
        } catch (NumberFormatException ex) {
            showError("视频间隔必须是有效的整数");
            intervalField.requestFocus();
            return false;
        }

        return true;
    }

    /**
     * 获取视频总时长（秒）
     */
    public long getVideoDuration(String videoPath) throws Exception {
        try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(videoPath)) {
            // 设置编码格式为UTF-8，解决读取元数据时的中文乱码
            System.setProperty("file.encoding", "UTF-8");
            grabber.start();
            long duration = grabber.getLengthInTime() / 1000000; // 转换为秒
            grabber.stop();
            return duration;
        }
    }

    /**
     * 切割单个视频片段
     */
    public void cutVideoSegment(String inputPath, String outputPath,
                                int startSecond, int durationSecond) throws Exception {
        
        // 设置FFmpeg的编码为UTF-8，解决中文路径问题
        System.setProperty("jna.encoding", "UTF-8");
        
        try (FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputPath)) {
            grabber.start();
            
            try (FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(
                    outputPath, 
                    grabber.getImageWidth(), 
                    grabber.getImageHeight(), 
                    grabber.getAudioChannels())) {
                
                // 配置输出参数
                recorder.setFormat("mp4");
                recorder.setFrameRate(grabber.getFrameRate());
                recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
                recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
                recorder.setVideoBitrate(grabber.getVideoBitrate());
                recorder.setAudioBitrate(grabber.getAudioBitrate());
                recorder.setSampleRate(grabber.getSampleRate());

                // 处理可能的中文路径问题
                recorder.setOption("output_ts_offset", "0");

                recorder.start();

                // 跳转到起始时间点（微秒）
                grabber.setTimestamp(TimeUnit.SECONDS.toMicros(startSecond));

                Frame frame;
                long endTime = TimeUnit.SECONDS.toMicros(startSecond + durationSecond);

                // 录制视频片段
                while ((frame = grabber.grab()) != null) {
                    if (grabber.getTimestamp() > endTime) {
                        break;
                    }
                    recorder.record(frame);
                }
            }
            grabber.stop();
        }
    }

    /**
     * 格式化时长（秒 -> 分:秒）
     */
    public String formatDuration(long seconds) {
        long minutes = seconds / 60;
        long remainingSeconds = seconds % 60;
        return String.format("%d分%d秒", minutes, remainingSeconds);
    }

    /**
     * 记录日志（线程安全）
     */
    public void log(String message) {
        SwingUtilities.invokeLater(() -> {
            logArea.append(message + "\n");
            logArea.setCaretPosition(logArea.getDocument().getLength());
        });
    }

    /**
     * 显示错误提示
     */
    public void showError(String message) {
        JOptionPane.showMessageDialog(this, message, "输入错误", JOptionPane.ERROR_MESSAGE);
    }


    public static void runVc() {
        // 设置默认编码为UTF-8
        System.setProperty("file.encoding", "UTF-8");

        // 在EDT线程中启动UI
        SwingUtilities.invokeLater(() -> {
            try {
                // 设置全局字体，确保中文显示正常
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                Font defaultFont = new Font("微软雅黑", Font.PLAIN, 12);
                UIManager.put("Label.font", defaultFont);
                UIManager.put("Button.font", defaultFont);
                UIManager.put("TextField.font", defaultFont);

                new VideoSplitterWithEncodingFix().setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }
}